package mips.value;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import mips.structure.MipsFunc;

public class Register extends MipsValue {
    // 这个类表示物理寄存器，在这里进行寄存器的分配
    private static final Map<Integer, Register> REGISTER_MAP = new HashMap<>();
    private static final List<Register> TEMP_REGISTERS = new ArrayList<>();
    private static final List<Register> SAVED_REGISTERS = new ArrayList<>();
    private static final List<Register> ARGUMENT_REGISTERS = new ArrayList<>();

    // 常数0
    public static final Register ZERO = new Register("$zero", 0, Type.SPECIAL);
    // 汇编器保留寄存器，由汇编器在特定场景（通常是加载大常数）自动生成
    public static final Register AT = new Register("$at", 1, Type.SPECIAL);
    // 函数返回值
    public static final Register V0 = new Register("$v0", 2, Type.RESULT);
    // 这个寄存器我用来存放一些特殊的值，所以不对外开放
    public static final Register V1 = new Register("$v1", 3, Type.SPECIAL);
    // 函数调用参数
    public static final Register A0 = new Register("$a0", 4, Type.ARGUMENT);
    public static final Register A1 = new Register("$a1", 5, Type.ARGUMENT);
    public static final Register A2 = new Register("$a2", 6, Type.ARGUMENT);
    public static final Register A3 = new Register("$a3", 7, Type.ARGUMENT);
    // 临时寄存器
    public static final Register T0 = new Register("$t0", 8, Type.TEMPORARY);
    public static final Register T1 = new Register("$t1", 9, Type.TEMPORARY);
    public static final Register T2 = new Register("$t2", 10, Type.TEMPORARY);
    public static final Register T3 = new Register("$t3", 11, Type.TEMPORARY);
    public static final Register T4 = new Register("$t4", 12, Type.TEMPORARY);
    public static final Register T5 = new Register("$t5", 13, Type.TEMPORARY);
    public static final Register T6 = new Register("$t6", 14, Type.TEMPORARY);
    public static final Register T7 = new Register("$t7", 15, Type.TEMPORARY);
    public static final Register T8 = new Register("$t8", 24, Type.TEMPORARY);
    public static final Register T9 = new Register("$t9", 25, Type.TEMPORARY);
    // 全局寄存器
    public static final Register S0 = new Register("$s0", 16, Type.TEMPORARY);
    public static final Register S1 = new Register("$s1", 17, Type.TEMPORARY);
    public static final Register S2 = new Register("$s2", 18, Type.TEMPORARY);
    public static final Register S3 = new Register("$s3", 19, Type.TEMPORARY);
    public static final Register S4 = new Register("$s4", 20, Type.TEMPORARY);
    public static final Register S5 = new Register("$s5", 21, Type.TEMPORARY);
    public static final Register S6 = new Register("$s6", 22, Type.TEMPORARY);
    public static final Register S7 = new Register("$s7", 23, Type.TEMPORARY);
    // 系统保留寄存器，在系统发生中断时使用
    // 我们这里用作全局寄存器
    public static final Register K0 = new Register("$k0", 26, Type.SAVED);
    public static final Register K1 = new Register("$k1", 27, Type.SAVED);
    // 维护函数的栈帧，用于访问局部变量和函数参数
    // 我们这里用作全局寄存器
    public static final Register FP = new Register("$fp", 30, Type.SAVED);
    // 全局指针，指向全局变量所在区域
    // 我们这里用作全局寄存器
    public static final Register GP = new Register("$gp", 28, Type.SAVED);
    // 栈帧寄存器
    public static final Register SP = new Register("$sp", 29, Type.SPECIAL);
    // 返回地址
    public static final Register RA = new Register("$ra", 31, Type.SPECIAL);

    // 为临时寄存器分配栈空间的偏移
    public static final Map<Register, Integer> TEMP_REGISTER_OFFSET = new HashMap<>();
    static {
        TEMP_REGISTER_OFFSET.put(T0, -8);
        TEMP_REGISTER_OFFSET.put(T1, -12);
        TEMP_REGISTER_OFFSET.put(T2, -16);
        TEMP_REGISTER_OFFSET.put(T3, -20);
        TEMP_REGISTER_OFFSET.put(T4, -24);
        TEMP_REGISTER_OFFSET.put(T5, -28);
        TEMP_REGISTER_OFFSET.put(T6, -32);
        TEMP_REGISTER_OFFSET.put(T7, -36);
        TEMP_REGISTER_OFFSET.put(T8, -40);
        TEMP_REGISTER_OFFSET.put(T9, -44);
        TEMP_REGISTER_OFFSET.put(S0, -48);
        TEMP_REGISTER_OFFSET.put(S1, -52);
        TEMP_REGISTER_OFFSET.put(S2, -56);
        TEMP_REGISTER_OFFSET.put(S3, -60);
        TEMP_REGISTER_OFFSET.put(S4, -64);
        TEMP_REGISTER_OFFSET.put(S5, -68);
        TEMP_REGISTER_OFFSET.put(S6, -72);
        TEMP_REGISTER_OFFSET.put(S7, -76);
    }

    // 枚举寄存器类型
    public enum Type {
        TEMPORARY, // 临时寄存器
        SAVED, // 保存寄存器
        ARGUMENT, // 参数寄存器
        RESULT, // 返回值寄存器
        SPECIAL// 特殊寄存器
    }

    private final String name;
    private final int index;
    private final Type type;

    private Register(String name, int index, Type type) {
        this.name = name;
        this.index = index;
        this.type = type;

        REGISTER_MAP.put(index, this); // 加入全局映射
        if (type == Type.TEMPORARY) {
            TEMP_REGISTERS.add(this);
        } else if (type == Type.SAVED) {
            SAVED_REGISTERS.add(this);
        } else if (type == Type.ARGUMENT) {
            ARGUMENT_REGISTERS.add(this);
        }
    }

    public static Register getArgumenRegister() {
        if (ARGUMENT_REGISTERS.size() == 0) {
            return null;
        }
        return ARGUMENT_REGISTERS.remove(0);
    }

    static int indesx = 0;

    public static Register getTempRegister(MipsFunc func) {
        if (TEMP_REGISTERS.size() == 0) {
            throw new RuntimeException("Out of temporary registers");
        }
        func.addRegister(TEMP_REGISTERS.get(0));
        return TEMP_REGISTERS.remove(0);
    }

    public static Register getZeroRegister() {
        return ZERO;
    }

    public static Register getSavedRegister() {
        if (SAVED_REGISTERS.size() == 0) {
            throw new RuntimeException("Out of saved registers");
        }
        return SAVED_REGISTERS.remove(0);
    }

    public static void releaseArgumentRegisters() {
        // 遍历所有的寄存器，如果是参数寄存器，就重新加入参数寄存器列表
        ARGUMENT_REGISTERS.clear();
        for (Register register : REGISTER_MAP.values()) {
            if (register.getType() == Type.ARGUMENT) {
                ARGUMENT_REGISTERS.add(register);
            }
        }
    }

    public static void releaseSavedRegisters() {
        // 遍历所有的寄存器，如果是保存寄存器，就重新加入保存寄存器列表
        SAVED_REGISTERS.clear();
        for (Register register : REGISTER_MAP.values()) {
            if (register.getType() == Type.SAVED) {
                SAVED_REGISTERS.add(register);
            }
        }
    }

    public static void releaseTempRegisters(MipsFunc func) {
        // 遍历所有的寄存器，如果是临时寄存器，就重新加入临时寄存器列表
        TEMP_REGISTERS.clear();
        func.getUsedRegisters().clear();
        for (Register register : REGISTER_MAP.values()) {
            if (register.getType() == Type.TEMPORARY) {
                TEMP_REGISTERS.add(register);
            }
        }
    }

    public static void releaseTempRegister(Register register, MipsFunc func) {
        // 释放一个临时寄存器
        TEMP_REGISTERS.add(register);
        func.removeRegister(register);
    }

    public static int getArgumentegistersCount() {
        return ARGUMENT_REGISTERS.size();
    }

    public static int getTempRegistersCount() {
        return TEMP_REGISTERS.size();
    }

    public static int getSavedRegistersCount() {
        return SAVED_REGISTERS.size();
    }

    public String getName() {
        return name;
    }

    public int getIndex() {
        return index;
    }

    public Type getType() {
        return type;
    }

    public static List<Register> getTempRegisters() {
        return TEMP_REGISTERS;
    }

    public static List<Register> getSavedRegisters() {
        return SAVED_REGISTERS;
    }

    public static List<Register> getArgumentRegisters() {
        return ARGUMENT_REGISTERS;
    }

    public static Register getRegisterByIndex(int index) {
        return REGISTER_MAP.get(index);
    }

    @Override
    public String toString() {
        return name;
    }
}
